AWS CDK で CloudFront Functions での JavaScript runtime 2.0 の選択がサポートされました
こんにちは、CX 事業本部 Delivery 部の若槻です。
先日に AWS CDK v2.118.0 がリリースされ、CloudFront Functions の L2 Construct で runtime
プロパティを設定可能になりました。
Features
- cloudfront: CloudFront Function runtime property (#28099) (9b466ae), closes #28163
当該のアップデートの Pull Request は以下になります。
このアップデートにより、AWS CDK による CloudFront Functions の構築で、新しいランタイムである JavaScript runtime 2.0 の選択がサポートされるようになりました。
CloudFront Functions のランタイムについて
CloudFront Functions が現在サポートしているランタイムは以下の 2 つです。
- JavaScript runtime 1.0
- JavaScript runtime 2.0
いずれも ECMAScript (ES) version 5.1 に準拠しているのに加え、古いランタイムである JavaScript runtime 1.0 が ES バージョン 6 から 9 の一部機能をサポートしているのに対して、新しいランタイムである JavaScript runtime 2.0 は ES バージョン 6 から 12 の一部機能に対応しています。
例えば、JavaScript runtime 2.0 は、1.0 に無い構文として以下をサポートしており、よりモダンなコードの記述が可能になっています。
async
await
const
let
() => 式
(アロー関数式)
上記のような追加の構文や機能の記述を使用した CloudFront Functions が、今回のアップデートにより AWS CDK で簡単に構成できるようになりました。
試してみた
AWS CDK で runtime
プロパティを指定して、JavaScript runtime 2.0 ランタイムの CloudFront Functions を構築してみます。
CDK ライブラリのアップグレード
AWS CDK のモジュールを v2.118.0 以上にアップグレードします。
npm i aws-cdk@latest aws-cdk-lib@latest
型定義の確認
node_modules
に生成された型定義を確認してみます。
FunctionProps には runtime
プロパティが追加されています。既定値は FunctionRuntime.JS_1_0
となっているので、JavaScript runtime 2.0 を使用する場合は明示的に設定が必要です。
/** * Properties for creating a CloudFront Function */ export interface FunctionProps { /** * A name to identify the function. * @default - generated from the `id` */ readonly functionName?: string; /** * A comment to describe the function. * @default - same as `functionName` */ readonly comment?: string; /** * The source code of the function. */ readonly code: FunctionCode; /** * The runtime environment for the function. * @default FunctionRuntime.JS_1_0 */ readonly runtime?: FunctionRuntime; }
FunctionRuntime プロパティです。2 つのランタイムがサポートされています。
/** * The function's runtime environment version. */ export declare class FunctionRuntime { readonly value: string; /** * cloudfront-js-1.0 */ static readonly JS_1_0: FunctionRuntime; /** * cloudfront-js-2.0 */ static readonly JS_2_0: FunctionRuntime; /** * A custom runtime string. * * Gives full control over the runtime string fragment. */ static custom(runtimeString: string): FunctionRuntime; private constructor(); }
実装
CloudFront Functions のコードです。Add security headers to the response のテンプレートを使用しています。JavaScript runtime 2.0 で新しくサポートされた async
および const
が使用されています。
async function handler(event) { const response = event.response; const headers = response.headers; // Set HTTP security headers // Since JavaScript doesn't allow for hyphens in variable names, we use the dict["key"] notation headers['strict-transport-security'] = { value: 'max-age=63072000; includeSubdomains; preload', }; headers['content-security-policy'] = { value: "default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'; frame-ancestors 'none'", }; headers['x-content-type-options'] = { value: 'nosniff' }; headers['x-frame-options'] = { value: 'DENY' }; headers['x-xss-protection'] = { value: '1; mode=block' }; headers['referrer-policy'] = { value: 'same-origin' }; // Return the response to viewers return response; }
CDK スタックのコードです。aws_cloudfront.Function
Construct で runtime
プロパティを指定して、JavaScript runtime 2.0 を使用するようにしています。
import { aws_cloudfront, aws_s3, aws_s3_deployment, aws_cloudfront_origins, Stack, RemovalPolicy, Duration, } from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class CdkSampleStack extends Stack { constructor(scope: Construct, id: string) { super(scope, id); // S3 バケットの作成 const websiteBucket = new aws_s3.Bucket(this, 'WebsiteBucket', { removalPolicy: RemovalPolicy.DESTROY, autoDeleteObjects: true, }); // CloudFront から S3 バケットへのアクセスを許可するために、 // Origin Access Identity を作成し、S3 バケットのアクセスポリシーに追加する const originAccessIdentity = new aws_cloudfront.OriginAccessIdentity( this, 'OriginAccessIdentity' ); websiteBucket.grantRead(originAccessIdentity); // CloudFront Function の作成 const cloudFrontFunction = new aws_cloudfront.Function( this, 'AddSecurityHeadersToTheResponseFunction', { code: aws_cloudfront.FunctionCode.fromFile({ filePath: 'src/cloudfront-function/add-security-headers-to-the-response/index.js', }), // JavaScript runtime 2.0 を指定 runtime: aws_cloudfront.FunctionRuntime.JS_2_0, } ); // CloudFront Destribution を作成 const distribution = new aws_cloudfront.Distribution(this, 'Distribution', { defaultRootObject: 'index.html', errorResponses: [ { ttl: Duration.minutes(5), httpStatus: 403, responseHttpStatus: 403, responsePagePath: '/error.html', }, { ttl: Duration.minutes(5), httpStatus: 404, responseHttpStatus: 404, responsePagePath: '/error.html', }, ], defaultBehavior: { viewerProtocolPolicy: aws_cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, origin: new aws_cloudfront_origins.S3Origin(websiteBucket, { originAccessIdentity, }), // CloudFront Function と Distribution の関連付け functionAssociations: [ { function: cloudFrontFunction, eventType: aws_cloudfront.FunctionEventType.VIEWER_RESPONSE, }, ], }, }); // S3 バケットへのコンテンツのデプロイ、CloudFront Distribution のキャッシュ削除 new aws_s3_deployment.BucketDeployment(this, 'WebsiteDeploy', { distribution, destinationBucket: websiteBucket, distributionPaths: ['/*'], sources: [ aws_s3_deployment.Source.data( '/index.html', '<html><body><h1>Hello, World!</h1></body></html>' ), aws_s3_deployment.Source.data( '/error.html', '<html><body><h1>Error!!!</h1></body></html>' ), aws_s3_deployment.Source.data('/favicon.ico', ''), ], }); } }
動作確認
前述のコードを CDK デプロイにより AWS アカウントにデプロイします。
JavaScript runtime 2.0 の CloudFront Function が作成されました。
CloudFront Function を Viewer response でテスト実行すると、レスポンスの出力にセキュリティヘッダーが付与されました。
ブラウザから CloudFront Distribution に実際にアクセスをすると、レスポンスにセキュリティヘッダーが付与されていることが確認できました。
各ランタイムバージョンのコード例
JavaScript runtime 1.0 および 2.0 のコード例は以下の公式ドキュメントにまとめられています。
次のような実際によくあるユースケースのサンプルが紹介されており、とても参考になるのでぜひ合わせてご確認ください。
- レスポンスに Cache-Control ヘッダーを追加する
- Cross-Origin Resource Sharing (CORS) ヘッダーをレスポンスに追加
- Cross-Origin Resource Sharing (CORS) ヘッダーをリクエストに追加
- レスポンスにセキュリティヘッダーを追加する
- リクエストに True-Client-IP ヘッダーを追加する
- ビューワーを新しい URL にリダイレクトさせる
- index.html を追加してファイル名を含まない URL をリクエストする
- リクエストのシンプルトークンを検証する
- クエリ文字列パラメータの正規化
おわりに
AWS CDK で CloudFront Functions での JavaScript runtime 2.0 の選択がサポートされたのでご紹介しました。
CloudFront Functions は Lambda@Edge とも異なる独自ランタイムを使用しています。今までは L2 Construct では JavaScript runtime 1.0 という構文や機能が比較的貧弱なランタイムのみサポートされていたのですが、今回のアップデートによりモダンな書き方ができる 2.0 が使用可能になりました。
公式ドキュメントでも JavaScript runtime 2.0 の利用が推奨されているので、今後 AWS CDK で新しく CloudFront Functions を構築する場合は、基本的には 2.0 を選択するようにしましょう。
以上